package me.jagar.chatvoiceplayerlibrary;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentTreeObserver;
import ohos.agp.components.Slider;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;

import java.math.BigDecimal;

public class PlayerVisualizerSeekbar extends Slider implements Component.EstimateSizeListener,
        ComponentContainer.ArrangeListener, Component.DrawTask {

    /**
     * 固定值为杆的高度
     */
    public static final int VISUALIZER_HEIGHT = 38;

    /**
     * 从文件转换的字节数组.
     */
    public byte[] bytes;

    /**
     * 当播放audioPlayer时，音频样本比例应该动态更新
     */
    private float denseness;

    /**
     * 画布绘画为样本尺度，填充播放部分音频样本
     */
    private Paint playedStatePainting = new Paint();
    /**
     * 画布绘画为样本尺度，填充未播放的部分音频样本
     */
    private Paint notPlayedStatePainting = new Paint();

    private int width = 0;
    private int height = 0;

    public PlayerVisualizerSeekbar(Context context) {
        super(context);
        init();
    }

    public PlayerVisualizerSeekbar(Context context, AttrSet attrs) {
        super(context, attrs);
        init();
    }

    public void setColors(Color playedColor, Color notPlayedColor) {
        playedStatePainting.setColor(notPlayedColor);
        notPlayedStatePainting.setColor(playedColor);
    }

    private void init() {
        bytes = null;
        playedStatePainting.setStrokeWidth(1f);
        playedStatePainting.setAntiAlias(true);
        notPlayedStatePainting.setStrokeWidth(1f);
        notPlayedStatePainting.setAntiAlias(true);
        getComponentTreeObserver().addWindowBoundListener(new ComponentTreeObserver.WindowBoundListener() {

            @Override
            public void onWindowBound() {
                width = getEstimatedWidth();
                height = getEstimatedHeight();
            }

            @Override
            public void onWindowUnbound() {

            }
        });
        addDrawTask(this::onDraw);
    }

    /**
     * 更新和重绘Visualizer视图
     *
     * @param bytes byte[]
     */
    public void updateVisualizer(byte[] bytes) {
        byte[] clone = bytes.clone();
        this.bytes = clone;
        invalidate();
    }

    /**
     * 更新播放器百分比。0 -文件未播放，1 -文件已完全播放
     *
     * @param percent percent
     */
    public void updatePlayerPercent(float percent) {
        denseness = (int) Math.ceil(width * percent);
        if (denseness < 0) {
            denseness = 0;
        } else if (denseness > width) {
            denseness = width;
        }
        invalidate();
    }

    @Override
    public boolean onArrange(int i, int i1, int i2, int i3) {
        return false;
    }

    @Override
    public boolean onEstimateSize(int i, int i1) {
        return false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (bytes == null || width == 0) {
            return;
        }
        float totalBarsCount = (float)width / dp(3);
        if (totalBarsCount <= 0.1f) {
            return;
        }
        byte value;
        int samplesCount = (bytes.length* 8 / 5);
        float samplesPerBar = samplesCount / totalBarsCount;
        float barCounter = 0;
        int nextBarNum = 0;

        int y = (height - dp(VISUALIZER_HEIGHT));
        int barNum = 0;
        int lastBarNum;
        int drawBarCount;

        for (int pos = 0; pos < samplesCount; pos++) {
            if (pos != nextBarNum) {
                continue;
            }
            drawBarCount = 0;
            lastBarNum = nextBarNum;
            while (lastBarNum == nextBarNum) {
                BigDecimal decimal = new BigDecimal(barCounter);
                BigDecimal decimal2 = new BigDecimal(samplesPerBar);
                barCounter = decimal.add(decimal2).floatValue();
                nextBarNum = Math.round(barCounter);
                drawBarCount++;
            }

            BigDecimal decimal = new BigDecimal(pos);
            BigDecimal decimal2 = new BigDecimal(5);
            int bitPointer = decimal.multiply(decimal2).intValue();
            int byteNum = bitPointer / Byte.SIZE;
            int byteBitOffset = bitPointer - byteNum * Byte.SIZE;
            int currentByteCount = Byte.SIZE - byteBitOffset;
            int nextByteRest = 5 - currentByteCount;
            value = (byte) ((bytes[byteNum] >> byteBitOffset) & ((2 << (Math.min(5, currentByteCount) - 1)) - 1));
            if (nextByteRest > 0) {
                value <<= nextByteRest;
                value |= bytes[byteNum + 1] & ((2 << (nextByteRest - 1)) - 1);
            }
            for (int b = 0; b < drawBarCount; b++) {
                int x = barNum * dp(3);
                float left = x;

                BigDecimal decima5 = new BigDecimal(y);
                int max = (int) Math.max(1, VISUALIZER_HEIGHT * value / 31.0f);
                int vp = vp(VISUALIZER_HEIGHT - max);
                BigDecimal decimal6 = new BigDecimal(vp);
                float top = decima5.add(decimal6).floatValue() ;
                float right = x + dp(2);
                float bottom = y + dp(VISUALIZER_HEIGHT);

                BigDecimal decimal3 = new BigDecimal(x);
                BigDecimal decimal4 = new BigDecimal(dp(2));
                if (x < denseness && decimal3.add(decimal4).floatValue() < denseness) {
                    canvas.drawRect(left, top, right, bottom, notPlayedStatePainting);
                } else {
                    canvas.drawRect(left, top, right, bottom, playedStatePainting);
                    if (x < denseness) {
                        canvas.drawRect(left, top, right, bottom, notPlayedStatePainting);
                    }
                }
                barNum++;
            }
        }
    }

    private int dp(float value) {
        if (value == 0) {
            return 0;
        }
        DisplayAttributes attributes = DisplayManager.getInstance().getDefaultDisplay(getContext()).get().getAttributes();
        return (int) Math.ceil(attributes.densityPixels * value);
    }

    private int vp(float value) {
        if (value == 0) {
            return 0;
        }
        DisplayAttributes attributes = DisplayManager.getInstance().getDefaultDisplay(getContext()).get().getAttributes();
        return (int)Math.ceil(attributes.densityPixels * value);
    }
}